package parse

import (
	"fmt"
	"net/url"
	"strconv"
	"strings"

	"gitee.com/samhula/gospider/utils"

	"github.com/PuerkitoBio/goquery"
)

// Rule HTML解析规则
type Rule struct {
	Selector string //css 查找规则
	Index    int    //取第几个元素
	Attr     string //获取属性
}

// Attr 属性取值
type Attr struct {
	Name string //属性名
	Tag  string //特殊取值标签own,abs，reg<own:href,abs:href,reg:/*/>
}

// isNavtive是否是css selector
func (r *Rule) isNative() bool {
	if r.Index == -1 && r.Attr == "" {
		return true
	}
	return false
}

// isText 是否是@@@
func (r *Rule) isText() bool {
	if r.Index == 0 && r.Attr == "" && r.Selector == "" {
		return true
	}
	return false
}

// getAttr 获取Attr结构体
func (r *Rule) getAttr() *Attr {
	if r.Attr == "" {
		return &Attr{
			Name: "",
			Tag:  "",
		}
	}
	//特殊属性:own,abs,reg
	name := r.Attr
	tag := ""
	if strings.HasPrefix(r.Attr, "own:") || strings.HasPrefix(r.Attr, "abs:") || strings.HasPrefix(r.Attr, "reg:") {
		tag = r.Attr[0:3]
		name = r.Attr[4:]
	}
	return &Attr{
		Name: name,
		Tag:  tag,
	}
}

// getString 获取
func (r *Rule) getContent(node *goquery.Selection, url *url.URL) string {
	//原生CSS Selector
	if r.isNative() {
		return node.Find(r.Selector).First().Text()
	}
	//自定义规则@@@
	if r.isText() {
		return node.Text()
	}
	//自定议规则解析
	if len(r.Selector) > 0 {
		selection := node.Find(r.Selector).Eq(r.Index)
		if selection.Nodes == nil || len(selection.Nodes) == 0 {
			return ""
		}
		return r.getAttrContent(selection, url)
	}
	return r.getAttrContent(node, url)
}

func (r *Rule) getAttrContent(node *goquery.Selection, refURL *url.URL) string {
	attr := r.getAttr()
	if attr.isText() {
		return node.Text()
	}
	//abs:只与href一起配合
	if attr.Tag == "abs" {
		abs, exist := node.Attr(attr.Name)
		if exist == false {
			return ""
		}
		absURL, err := refURL.Parse(abs)
		if err != nil {
			return ""
		}
		return absURL.String()
	}
	//own
	if attr.Tag == "own" {
		text := node.First().Text()
		if len(attr.Name) > 0 {
			return utils.RegexText(attr.Name, text)
		}
		return text
	}
	//reg
	if attr.Tag == "reg" {
		text := node.Text()
		if len(attr.Name) > 0 {
			return utils.RegexText(attr.Name, text)
		}
		return text
	}
	return node.Text()
}

// isText 是否是获取字符串
func (a *Attr) isText() bool {
	if a.Tag == "" && a.Name == "" {
		return true
	}
	return false
}

// NewRule 把ruleStr转成Rule
func NewRule(ruleStr string) (*Rule, error) {
	//#id
	if strings.Index(ruleStr, "@") == -1 {
		return &Rule{
			Selector: ruleStr,
			Index:    -1,
			Attr:     "",
		}, nil
	}
	//rule 至少是@@@
	if len(ruleStr) < 3 {
		return nil, fmt.Errorf("%v:format error", ruleStr)
	}
	//分解
	ruleArr := strings.Split(ruleStr, "@")
	index, _ := strconv.Atoi(ruleArr[2])
	rule := &Rule{
		Selector: ruleArr[1],
		Index:    index,
		Attr:     ruleArr[3],
	}
	return rule, nil
}
